﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Xml.Linq;
using System.Globalization;

using Pg.BioMedics.SDR.Entities;
using Pg.BioMedics.SDR.Entities.Codes;

namespace Pg.BioMedics.SDR.Services
{
    /// <summary>
    /// Provides static routines supporting tokens extraction from MPEG-7 SCD document
    /// </summary>
    internal static class Mpeg7Helper
    {
        #region Static methods

        /// <summary>
        /// Extracts list of tokens encapsulated in the SCD document
        /// </summary>
        /// <param name="scdXml">MPEG-7 SCD document</param>
        /// <returns>List of tokens</returns>
        internal static IList<Token> ExtractTokens(string scdXml)
        {
            XDocument document = XDocument.Parse(scdXml);
            
            // find all word tokens
            var wordLinks = from wordLink in document.Descendants("WordLink")
                            let tokenIndex = TryParseInt32(wordLink.Attribute("word").Value)
                            let wordToken = (from wordToken in document.Descendants("Token")
                                             where (wordToken.Parent != null) &&
                                                   (wordToken.Parent.Name == "WordLexicon") &&
                                                   (wordToken.Attribute("word") != null)
                                             select wordToken).GetByIndex(tokenIndex.Value)
                            where (wordToken != null) &&
                                  (wordLink.Parent != null) &&
                                  (wordLink.Parent.Name == "Node") &&
                                  (wordLink.Attribute("word") != null) &&
                                  (TryParseInt32(wordLink.Attribute("word").Value) != null)
                            select new Token()
                            {
                                Value = wordToken.Attribute("word").Value,
                                TypeCode = wordToken.Attribute("linguisticUnit").Value == "word" ? TokenTypeCodes.Word : TokenTypeCodes.NonSpeech,
                                AcousticScore = TryParseDouble(wordLink.Attribute("acousticScore").Value),
                                Probability = TryParseDouble(wordLink.Attribute("probability").Value),
                                Offset = TryParseInt32(wordLink.Parent.Attribute("timeOffset").Value)
                            };

            // return results
            return wordLinks.ToList();
        }

        #endregion

        #region Extension methods

        internal static T GetByIndex<T>(this IEnumerable<T> collection, int index)
        {
            return (T)collection.ToArray().GetValue(index);
        }

        #endregion

        #region Support methods

        private static double? TryParseDouble(string value)
        {
            double result = 0;
            
            if (Double.TryParse(value, NumberStyles.Any, NumberFormatInfo.InvariantInfo, out result))
                return result;
            else
                return null;
        }

        private static int? TryParseInt32(string value)
        {
            int result = 0;
            if (Int32.TryParse(value, out result))
                return result;
            else
                return null;
        }

        #endregion
    }
}
